; *******************************************************************
;   log4ahk_PopUpAppender.ahk
; *******************************************************************

; -------------------------------------------------------------------
;   log4ahk_viewer_GuiPos
; -------------------------------------------------------------------

class log4ahk_viewer_GuiPos
{
  __New(offset=0, size=32, start=0)
  {
    this.offset := offset
    this.size   := size
    this.step   := start
    this.inc    := 1
  }
  
  next(increment=1)
  {
    this.step += increment
    return this.get()
  }
  
  n(increment=1)
  {
    this.step += increment
    return this.get()
  }
  
  get()
  {
    return this.offset + this.step * this.size
  }
  
  __Get(aName)
  {
    if aName in v,n
    {
      if (aName = "v")
        return this.get()
      if (aName = "n")
        return this.next(this.inc)
    }
  }
}

; -------------------------------------------------------------------
;   log4ahk_PopUpAppender
; -------------------------------------------------------------------

class log4ahk_PopUpAppender extends log4ahk_appender
{
  __New(GuiName = "PopUpAppender")
  {
    base.__New(GuiName)
    this.Events := []
    global log4ahk_PopUpAppender_Inst := this

    this.gui_controls := {}
    this.GuiName := GuiName
    this.gui_new()

    ypos := new log4ahk_viewer_GuiPos(8, 8)
    xpos := new log4ahk_viewer_GuiPos(4, 8)
    yn   := 3
    xn   := 7
    xpos.inc := xn
    ypos.inc := yn
    
    c := this.gui_controls
    
    xpos.step := 0
    c.search   := this.add_txt(xpos.v,ypos.v,"&Search:")
    c.edit     := this.add_edt(xpos.n,ypos.v-4)
    c.reset    := this.add_cbx(xpos.next(3*xn),ypos.v,"Reset")
    c.regex    := this.add_cbx(xpos.n,ypos.v,"Regex")
    c.match    := this.add_cbx(xpos.n,ypos.v,"Match case")
    c.disable  := this.add_cbx(xpos.next(2*xn),ypos.v,"Disable")

    xpos.step := 0
    c.options  := this.add_txt(xpos.v,ypos.n,"&Options:")
    c.log      := this.add_cbx(xpos.n,ypos.v,"Log")
    c.wrap     := this.add_cbx(xpos.n,ypos.v,"Wrap")
    c.newest   := this.add_cbx(xpos.n,ypos.v,"Newest at the top")

    xpos.step := 0
    xpos.n
    xpos.n
    xpos.n
    c.listview := this.add_lvw(xpos.v,ypos.n,600,280,"Grid vlog4ahk_lv")
    Gui %GuiName%:Default
    LV_InsertCol(99, "AutoHdr", "Logger")
    LV_InsertCol(99, "AutoHdr", "Date & Time")
    LV_InsertCol(99, "AutoHdr", "Level")
    LV_InsertCol(99, "AutoHdr", "Message")
    
    xpos.step := 0
    ypos.inc := 2
    Gui Font, bold
    c.filters := this.add_txt(xpos.v,ypos.v,"&Level:")
    Gui Font, norm
    ystep := ypos.step
    xpos.offset := 8
    c.trace   := this.add_cbx(xpos.v,ypos.n,"TRACE")
    c.debug   := this.add_cbx(xpos.v,ypos.n,"DEBUG")
    c.info    := this.add_cbx(xpos.v,ypos.n,"INFO")
    c.error   := this.add_cbx(xpos.v,ypos.n,"ERROR")
    c.fatal   := this.add_cbx(xpos.v,ypos.n,"FATAL")
    c.all     := this.add_cbx(xpos.v,ypos.n,"ALL")
    
    Gui Font, bold
    ypos.n
    c.filters := this.add_txt(xpos.v,ypos.n,"&Logger:")
    Gui Font, norm
    
    loop 6
    {
      c["logname" . A_Index] := this.add_cbx(xpos.v,ypos.n,"loggernameorclass")
      this.gui_hide("logname" . A_Index)
      this.gui_setcheck("logname" . A_Index)
    }
      
    this.loggers := []

    this.gui_settext("edit", ".*")
    this.gui_setcheck("debug")
    
    Gui %GuiName%:Show, Hide, PopUpAppender
  }

  ; -------------------------------------------------------------------
  ;   filter_items
  ; -------------------------------------------------------------------
  
  filter_items(logger, time, level, msg)
  {
    RegEx := this.gui_gettext("edit")
    logchecked := false
    for k,v in this.loggers
    {
      if (v == logger)
        logchecked := this.gui_checked("logname" . k)
    }

    StringLower lev, level
    if (this.gui_checked(lev) && (RegExMatch(msg, RegEx) != 0) && logchecked)
      return true
    else
      return false
  }
  
  ; -------------------------------------------------------------------
  ;   set_listview
  ; -------------------------------------------------------------------
  
  set_listview(txt)
  {
    GuiName := this.GuiName
    Gui %GuiName%:Default
    LV_Delete()
    
    for k,v in this.events
    {
      if (this.filter_items(v.logger, v.time, v.level, v.msg))
        LV_Add("", v.logger, v.time, v.level, v.msg)
    }
    
    Loop, parse, txt, `n, `r
    {
      RegExMatch(A_LoopField, "O)LOG: ([0-9]{1,2}[.] [a-zA-Z]{1,12} [0-9]{2,4}), ([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}) (TRACE|ERROR|INFO|DEBUG|FATAL) (.*)", match)
      date  := match.Value(1)
      time  := match.Value(2)
      level := match.Value(3)
      msg   := match.Value(4)
      logger := this.events[A_Index].logger.name
      vtime   := this.events[A_Index].time
      FormatTime vtimeout, %vtime%, HH:mm:ss
      ;if (this.filter_items(logger, vtimeout, level, msg))
      ;  LV_Add("", logger, vtimeout, level, msg)
    }
    LV_ModifyCol()
  }
  
  append(event)
  {
    this.text .= this.layout.format(event) . "`n"
    ev := {}
    ev.logger := event.logger.name
    ev.time   := event.time
    ev.msg    := event.message
    ev.level  := this.Level2Name(event.level)
    this.events.insert(ev)
    
    newlogger := true
    for k,v in this.loggers
    {
      if(v == event.logger.name)
      {
        newlogger := false
        break
      }
    }
    if (newlogger)
    {
      this.loggers.insert(event.logger.name)
      this.gui_show("logname" . this.loggers.MaxIndex())
      this.gui_settext("logname" . this.loggers.MaxIndex(), this.loggers[this.loggers.MaxIndex()])
    }
      
    this.set_listview(this.text)
  }
  
  Level2Name(level)
  {
    if (Level = log4ahk_logger.LevelTrace)
      return "TRACE"
    if (Level = log4ahk_logger.LevelDebug)
      return "DEBUG"
    if (Level = log4ahk_logger.LevelInfo)
      return "INFO"
    if (Level = log4ahk_logger.LevelWarn)
      return "WARN"
    if (Level = log4ahk_logger.LevelError)
      return "ERROR"
    if (Level = log4ahk_logger.LevelFatal)
      return "FATAL"
  }
  
  
  ; -------------------------------------------------------------------
  ;   gui helper
  ; -------------------------------------------------------------------
  
  gui_new()
  {
    GuiName := this.GuiName
    Gui %GuiName%:New 
    Gui %GuiName%:+Resize
    Gui %GuiName%:+Labellog4ahk_on
  }
  
  gui_add(type, options = "", text = "")
  {
    global
    local GuiName, opt, Out
    GuiName := this.GuiName
    opt := "HwndOut " . options
    Gui %GuiName%:Add, %type%, %opt%, %text%
    return Out
  }
  
  add_txt(x, y, text = "", options = "")
  {
    opt := "X" . x . " Y" . y . " " . options
    return this.gui_add("Text", opt, text)
  }

  add_lvw(x, y, w, h, options = "")
  {
    opt := "X" . x . " Y" . y . " W" . w . " H" . h . " " . options
    return this.gui_add("ListView", opt)
  }

  add_edt(x, y, text = "", options = "")
  {
    opt := "X" . x . " Y" . y . " " . options . " glog4ahk_filter"
    return this.gui_add("Edit", opt, text)
  }

  add_cbx(X, Y, text = "", options = "")
  {
    opt := "X" . x . " Y" . y . " " . options . " glog4ahk_filter"
    return this.gui_add("Checkbox", opt, text)
  }
  
  add_gbx(X, Y, W, H, text = "", options = "")
  {
    opt := "x" . X . " y" . Y . " w" . W . " h" . H . " " . options
    return this.gui_add("GroupBox", opt, text)
  }
  
  gui_settext(controlname, text)
  {
    hwnd := this.gui_controls[controlname]
    ControlSetText, , %text% , ahk_id %hwnd%, 

    l := log4ahk.getLogger("test")
    l.error("gui_settext.controlname: " . controlname)
    l.error("gui_settext.hwnd: " . hwnd)
  }

  gui_gettext(controlname)
  {
    hwnd := this.gui_controls[controlname]
    ControlGetText, out, , ahk_id %hwnd%
    return out
  }

  gui_setcheck(controlname)
  {
    hwnd := this.gui_controls[controlname]
    Control Check, , , ahk_id %hwnd%
  }

  gui_checked(controlname)
  {
    hwnd := this.gui_controls[controlname]
    ControlGet out, Checked, , , ahk_id %hwnd%
    return out
  }

  gui_uncheck(controlname)
  {
    hwnd := this.gui_controls[controlname]
    Control Uncheck, , , ahk_id %hwnd%
  }

  gui_hide(controlname := "")
  {
    if (controlname = "")
    {
      GuiName := this.GuiName
      Gui %GuiName%:Show, Hide
    }
    else
    {
      hwnd := this.gui_controls[controlname]
      Control Hide, , , ahk_id %hwnd%
    }
  }

  gui_show(controlname := "")
  {
    if (controlname = "")
    {
      GuiName := this.GuiName
      Gui %GuiName%:Show
    }
    else
    {
      hwnd := this.gui_controls[controlname]
      Control Show, , , ahk_id %hwnd%
    }
  }

  update(c)
  {
    this.set_listview(this.text)
  }

  filter_cb(c)
  {
    l := log4ahk.getLogger("test")
    if (c == "Log")
    {
    	    l.info("log selected")
    }
    checked := this.gui_checked(c)
    trace_checked := this.gui_checked("trace")
    debug_checked := this.gui_checked("debug")
    info_checked  := this.gui_checked("info")
    error_checked := this.gui_checked("error")
    fatal_checked := this.gui_checked("fatal")
    if (c == "all" && checked)
    {
      this.gui_setcheck("trace")
      this.gui_setcheck("debug")
      this.gui_setcheck("info")
      this.gui_setcheck("error")
      this.gui_setcheck("fatal")
    }
    else if (c == "all" && !checked)
    {
      if (this.do_gui_uncheck_all)
      {
      	this.do_gui_uncheck_all := false
      	return
      }
      this.gui_uncheck("trace")
      this.gui_uncheck("debug")
      this.gui_uncheck("info")
      this.gui_uncheck("error")
      this.gui_uncheck("fatal")
    }
    else if (trace_checked && debug_checked && info_checked && error_checked && fatal_checked)
    {
      this.gui_setcheck("all")
    }
    else
    {
      this.do_gui_uncheck_all := true
      this.gui_uncheck("all")
    }
  }

  size(w, h)
  {
    stdlib_anchor("log4ahk_lv",     "wh")
    stdlib_anchor("config_btn_save",    "x", true)
  }
  
}

log4ahk_filter:
  log4ahk_PopUpAppender_Inst.update(A_GuiControl)
  log4ahk_PopUpAppender_Inst.filter_cb(A_GuiControl)
return

log4ahk_onSize:
  log4ahk_PopUpAppender_Inst.size(A_GuiWidth, A_GuiHeight)
Return

